﻿using BuildPlannerLib.Enums;
using BuildPlannerLib.SimEvents;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BuildPlannerLib
{
    // Class for setting and defining properties for bases on the map
    public class Base
    {
        // BaseStatus enum field sets whether there is a CC/Hatch/Nexus started/finished at the base
        public BaseStatus Status;

        // Field for the total number of workers assigned to minerals at the base
        public int MineralWorkers;

        // index 0 = Leaving - Headed toward minerals (1st priority to build buildings for T/Z)
        // index 1 = Close - Have travelled far enough to start mining at close patches (2nd priority to build buildings for T/Z)
        // index 2 = Idle - Have travelled far enough to mine at any patch (3rd priority to build buildings for T/Z)
        public int[] MineralWorkerStatus;

        // MineralPatches = Total number of mineral patches of that type at the base
        // Idle = Not currently being mined
        // MULEIdle = No MULE attached (Because MULE mining is strange, I'm going to start with 1 MULE per patch.)

        // index 0 = Standard Yield, Far Mineral Patch
        // index 1 = Gold Yield, Far Mineral Patch
        // index 2 = Standard Yield, Close Mineral Patch
        // index 3 = Gold Yield, Close Mineral Patch

        public int[] MineralPatches;
        public int[] IdleMineralPatches;
        public int[] MULEIdleMineralPatches;

        // GasWorkers = Total assigned to gas at the base
        public int GasWorkers;

        // index 0 = Leaving - Headed toward gas geyser
        // index 1 = Idle - Have travelled far enough to mine, but the geyser is in use

        public int[] GasWorkerStatus;

        // I'm ignoring geyser distance temporarily, since there are no hard numbers to work with yet.

        // index 0 = 4 Yield Geyser
        // index 1 = 6 Yield "Rich" Geyser
        // index 2 = 8 Yield "Rich" Geyser (used on some proleague maps with single geyser)

        // GasGeysers = Total number of gas geysers of that type at the base.
        // Started = Started Refinery/Assimilator/Extractor on geyser.
        // Converted = Finished Refinery/Assimilator/Extractor on geyser.
        // Idle = Not currently being mined.

        public int[] GasGeysers;
        public int[] StartedGasGeysers;
        public int[] ConvertedGasGeysers;
        public int[] IdleGasGeysers;

        // Constructor with fields for mineral layout and gas layout
        public Base(int[] minerallayout, int[] gaslayout)
        {
            Status = BaseStatus.NotTaken;

            MineralWorkerStatus = new int[] { 0, 0, 0 };
            GasWorkerStatus = new int[] { 0, 0 };
            MineralPatches = new int[4];
            IdleMineralPatches = new int[4];
            MULEIdleMineralPatches = new int[4];
            GasGeysers = new int[3];
            IdleGasGeysers = new int[3];
            StartedGasGeysers = new int[] { 0, 0, 0 };
            ConvertedGasGeysers = new int[] { 0, 0, 0 };

            // minerallayout[] is an array of int values that indicates the number of mineral patches at the base.
            // Copies the array to MineralPatches, IdleMineralPatches, and MULEIdleMineralPatches.

            Array.Copy(minerallayout, MineralPatches, 4);
            Array.Copy(minerallayout, IdleMineralPatches, 4);
            Array.Copy(minerallayout, MULEIdleMineralPatches, 4);

            // gaslayout[] is an array of int values that indicates the number of gas geysers at the base.
            // Copies the array to GasGeysers and IdleGasGeysers.

            Array.Copy(gaslayout, GasGeysers, 3);
            Array.Copy(gaslayout, IdleGasGeysers, 3);
        }

        // Starts an expansion at the base
        public void StartExpansion()
        {
            Status = BaseStatus.ExpandStarted;
        }

        // Finishes an expansion at the base
        public void FinishExpansion()
        {
            Status = BaseStatus.ExpandFinished;
        }

        // Adds a workers to minerals
        public void AddMineralWorker(ref Build build)
        {
            MineralWorkers++;
            MineralWorkerStatus[0]++;
            int newTime = TimeConvert.ToInt(build.CurrentTime) + 186;
            build.EventList.Add(new ReachCloseMinerals(build, this, newTime));
        }

        // Removes a worker from minerals
        public void RemoveMineralWorker(ref Build build)
        {
            // Remove from the total number of workers
            MineralWorkers--;

            // Remove from Leaving, then Close, then Idle.
            SimEvent rem;
            if (MineralWorkerStatus[0] > 0)
            {
                MineralWorkerStatus[0]--;
                rem = build.EventList.OfType<ReachCloseMinerals>().First<ReachCloseMinerals>(obj => obj.GetBase() == this);
                build.EventList.Remove(rem);
            }
            else if (MineralWorkerStatus[1] > 0)
            {
                MineralWorkerStatus[1]--;
                rem = build.EventList.OfType<ReachFarMinerals>().First<ReachFarMinerals>(obj => obj.GetBase() == this);
                build.EventList.Remove(rem);

            }
            else if (MineralWorkerStatus[2] > 0)
            {
                MineralWorkerStatus[2]--;
            }
            else
            {
                // Placeholder for exception
            }
        }

        // Starts a Refinery/Assimilator/Extractor
        public void StartGasConversion()
        {
            // Start converting SuperRich, then Rich, then Normal
            if (GasGeysers[2] > StartedGasGeysers[2])
            {
                StartedGasGeysers[2]++;
            }
            else if (GasGeysers[1] > StartedGasGeysers[1])
            {
                StartedGasGeysers[1]++;
            }
            else if (GasGeysers[0] > StartedGasGeysers[0])
            {
                StartedGasGeysers[0]++;
            }
            else
            {
                // Placeholder
            }
        }

        // Finishes a Refinery/Assimilator/Extractor
        public void FinishGasConversion()
        {
            // Finish converting SuperRich, then Rich, then Normal
            if (StartedGasGeysers[2] > ConvertedGasGeysers[2])
            {
                ConvertedGasGeysers[2]++;
            }
            else if (StartedGasGeysers[1] > ConvertedGasGeysers[1])
            {
                ConvertedGasGeysers[1]++;
            }
            else if (StartedGasGeysers[0] > ConvertedGasGeysers[0])
            {
                ConvertedGasGeysers[0]++;
            }
            else
            {
                // Placeholder
            }
        }

        // Adds a worker to gas
        public void AddGasWorker(ref Build build)
        {
            // Add to the total number of workers and Leaving workers
            GasWorkers++;
            GasWorkerStatus[0]++;
            int newTime = TimeConvert.ToInt(build.CurrentTime) + 211;
            build.EventList.Add(new ReachGasGeysers(build, this, newTime));
        }

        // Removes a worker from gas
        public void RemoveGasWorker(ref Build build)
        {
            // Remove from total number of workers
            GasWorkers--;

            // Remove from Leaving, then Idle
            if (GasWorkerStatus[0] > 0)
            {
                GasWorkerStatus[0]--;
                SimEvent rem = build.EventList.OfType<ReachGasGeysers>().First<ReachGasGeysers>(obj => obj.GetBase() == this);
                build.EventList.Remove(rem);
            }
            else if (GasWorkerStatus[1] > 0)
            {
                GasWorkerStatus[1]--;
            }
            else
            {
                // Placeholder
            }
        }

        // Sets the base to the state at the start of simulation
        public void Reset()
        {
            // Set all mineral patches to idle
            Array.Copy(MineralPatches, IdleMineralPatches, 4);
            Array.Copy(MineralPatches, MULEIdleMineralPatches, 4);

            // Unconvert and make idle all gas geysers
            Array.Copy(GasGeysers, IdleGasGeysers, 3);
            StartedGasGeysers[0] = 0;
            ConvertedGasGeysers[0] = 0;

            StartedGasGeysers[1] = 0;
            ConvertedGasGeysers[1] = 0;

            StartedGasGeysers[2] = 0;
            ConvertedGasGeysers[2] = 0;

            // Set all worker counts to 0
            MineralWorkers = 0;
            MineralWorkerStatus[0] = 0;
            MineralWorkerStatus[1] = 0;
            MineralWorkerStatus[2] = 0;

            GasWorkers = 0;
            GasWorkerStatus[0] = 0;
            GasWorkerStatus[1] = 0;

            // Set BaseStatus to NotTaken
            Status = BaseStatus.NotTaken;
        }
        // This method dynamically sets the limit of the number of gas workers at the base.
        public int GasWorkerCapacity()
        {
            return (ConvertedGasGeysers.Sum() * 3);
        }
    }
}
